home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / misc / gs261src.zip / stream.c < prev    next >
C/C++ Source or Header  |  1993-05-13  |  14KB  |  496 lines

  1. /* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* stream.c */
  20. /* Stream package for Ghostscript interpreter */
  21. #include "stdio_.h"        /* includes std.h */
  22. #include "memory_.h"
  23. #include "gpcheck.h"
  24. #include "stream.h"
  25. #include "scanchar.h"
  26.  
  27. /* Forward declarations */
  28.     /* Generic */
  29. /* Export these for filters */
  30. void
  31.   s_std_init(P5(stream *, byte *, uint, const stream_procs *, int /*mode*/));
  32. int
  33.   s_std_null(P1(stream *)),
  34.   s_std_noavailable(P2(stream *, long *)),
  35.   s_std_noseek(P2(stream *, long));
  36.     /* Strings */
  37. private int
  38.   s_string_read_buf(P1(stream *)),
  39.   s_string_write_buf(P1(stream *)),
  40.   s_string_available(P2(stream *, long *)),
  41.   s_string_seek(P2(stream *, long));
  42. private void
  43.   s_string_init(P4(stream *, byte *, uint, const stream_procs *));
  44.     /* Files */
  45. private int
  46.   s_file_read_buf(P1(stream *)),
  47.   s_file_available(P2(stream *, long *)),
  48.   s_file_read_seek(P2(stream *, long)),
  49.   s_file_read_close(P1(stream *));
  50. private int
  51.   s_file_write_buf(P1(stream *)),
  52.   s_file_write_seek(P2(stream *, long)),
  53.   s_file_write_flush(P1(stream *)),
  54.   s_file_write_close(P1(stream *));
  55.  
  56. /* ------ Generic procedures ------ */
  57.  
  58. /* Standard stream initialization */
  59. void
  60. s_std_init(register stream *s, byte *ptr, uint len, const stream_procs *pp,
  61.   int modes)
  62. {    s->cbuf = ptr;
  63.     s->cptr = ptr - 1;
  64.     s->endptr = (!(modes & s_mode_read) ? s->cptr + len : s->cptr);
  65.     s->modes = modes;
  66.     s->end_status = 0;
  67.     s->position = 0;
  68.     s->bsize = s->cbsize = len;
  69.     s->strm = 0;            /* not a filter */
  70.     s->procs = *pp;
  71. }
  72.  
  73. /* Implement a stream procedure as a no-op. */
  74. int
  75. s_std_null(stream *s)
  76. {    return 0;
  77. }
  78.  
  79. /* Flush data to end-of-file when reading. */
  80. int
  81. s_std_read_flush(stream *s)
  82. {    while ( 1 )
  83.     {    s->cptr = s->endptr;
  84.         if ( s->end_status ) break;
  85.         (*s->procs.read_buf)(s);
  86.     }
  87.     return (s->end_status == EOFC ? 0 : s->end_status);
  88. }
  89.  
  90. /* Flush buffered data when writing. */
  91. int
  92. s_std_write_flush(stream *s)
  93. {    return (*s->procs.write_buf)(s);
  94. }
  95.  
  96. /* Indicate an error when asked for available input bytes. */
  97. int
  98. s_std_noavailable(stream *s, long *pl)
  99. {    return ERRC;
  100. }
  101.  
  102. /* Indicate an error when asked to seek. */
  103. int
  104. s_std_noseek(stream *s, long pos)
  105. {    return ERRC;
  106. }
  107.  
  108. /* Standard stream finalization.  Disable the stream. */
  109. void
  110. s_disable(register stream *s)
  111. {    s->bsize = 0;
  112.     s->modes = 0;
  113.     /****** SHOULD DO MORE THAN THIS ******/
  114. }
  115.  
  116. /* ------ Implementation-independent procedures ------ */
  117.  
  118. /* Close a stream, disabling it if successful. */
  119. int
  120. sclose(register stream *s)
  121. {    int code = (*s->procs.close)(s);
  122.     if ( code < 0 )
  123.         return code;
  124.     s_disable(s);
  125.     return code;
  126. }
  127.  
  128. /* Implement sgetc when the buffer may be empty. */
  129. /* If the buffer really is empty, refill it and then read a byte. */
  130. int
  131. spgetc(register stream *s)
  132. {    int code;
  133.     if ( !sendbufp(s) )
  134.         return *++(s->cptr);
  135.     if ( s->end_status )
  136.         return s->end_status;
  137.     code = (*s->procs.read_buf)(s);
  138.     if ( code < 0 )
  139.         return code;
  140.     if ( !sendbufp(s) )
  141.         return *++(s->cptr);
  142.     return (s->end_status ? s->end_status : EOFC);
  143. }
  144.  
  145. /* Implementing sputc when the buffer is full, */
  146. /* by flushing the buffer and then writing the byte. */
  147. int
  148. spputc(register stream *s, byte b)
  149. {    int code;
  150.     if ( s->end_status ) return s->end_status;
  151.     code = (*s->procs.write_buf)(s);
  152.     if ( code < 0 ) return code;
  153.     return sputc(s, b);
  154. }
  155.  
  156. /* Push back a character onto a (read) stream. */
  157. /* The character must be the same as the last one read. */
  158. /* Return 0 on success, ERRC on failure. */
  159. int
  160. sungetc(register stream *s, byte c)
  161. {    if ( !s_is_reading(s) || s->cptr < s->cbuf || *(s->cptr) != c )
  162.         return ERRC;
  163.     s->cptr--;
  164.     return 0;
  165. }
  166.  
  167. /* Read a string from a stream. */
  168. /* Return the number of bytes read. */
  169. uint
  170. sgets(register stream *s, byte *str, uint rlen)
  171. {    uint len = rlen;
  172.     while ( len > 0 )
  173.        {    uint count = sbufavailable(s);
  174.         if ( count == 0 )
  175.            {    int code;
  176.             if ( s->end_status )
  177.                 return rlen - len;
  178.             code = (*s->procs.read_buf)(s);
  179.             if ( code < 0 || sendbufp(s) )
  180.                 return rlen - len;
  181.             continue;
  182.            }
  183.         if ( count > len ) count = len;
  184.         memcpy(str, s->cptr + 1, count);
  185.         s->cptr += count;
  186.         str += count;
  187.         len -= count;
  188.        }
  189.     return rlen;
  190. }
  191.  
  192. /* Write a string on a stream. */
  193. /* Return the number of bytes written. */
  194. uint
  195. sputs(register stream *s, const byte *str, uint wlen)
  196. {    uint len = wlen;
  197.     if ( wlen > s->bsize && s->procs.write_buf == s_file_write_buf )
  198.        {    /* Write directly on the file. */
  199.         uint write_count;
  200.         (*s->procs.write_buf)(s);
  201.         write_count = fwrite(str, 1, wlen, s->file);
  202.         if ( s_can_seek(s) )
  203.             s->position = ftell(s->file);
  204.         gp_check_interrupts();
  205.         return write_count;
  206.        }
  207.     while ( len > 0 )
  208.        {    uint count = sbufavailable(s);
  209.         if ( count > 0 )
  210.            {    if ( count > len ) count = len;
  211.             memcpy(s->cptr + 1, str, count);
  212.             s->cptr += count;
  213.             str += count;
  214.             len -= count;
  215.            }
  216.         else
  217.            {    byte ch = *str++;
  218.             sputc(s, ch);
  219.             if ( s->end_status ) return wlen - len;
  220.             len--;
  221.            }
  222.        }
  223.     return wlen;
  224. }
  225.  
  226. /* Read a hex string from a stream. */
  227. /* Answer EOFC if we reached end-of-file before filling the string, */
  228. /* 0 if we filled the string first, or ERRC on error. */
  229. /* s->odd should be -1 initially: */
  230. /* if an odd number of hex digits was read, s->odd is set to */
  231. /* the odd digit value, otherwise s->odd is set to -1. */
  232. /* If ignore_garbage is true, characters other than hex digits are ignored; */
  233. /* if ignore_garbage is false, characters other than hex digits or */
  234. /* whitespace return an error. */
  235. int
  236. sreadhex(stream *s, byte *str, uint rlen, uint *nread,
  237.   int *odd_digit, int ignore_garbage)
  238. {    byte *ptr = str;
  239.     byte *limit = ptr + rlen;
  240.     byte val1 = (byte)*odd_digit;
  241.     byte val2;
  242.     byte save_last;
  243.     register byte _ds *decoder = scan_char_decoder;
  244.     s_declare_inline(s, sptr, endp);
  245.     int ch;
  246.     int code;
  247.     if ( rlen == 0 )
  248.        {    *nread = 0;
  249.         return 0;
  250.        }
  251.     s_begin_inline(s, sptr, endp);
  252.     if ( val1 <= 0xf ) goto d2;
  253. d1:    /* Fast check for common case */
  254.     if ( sptr >= endp ) goto x1;    /* no last char to save */
  255.     save_last = *endp;
  256.     *endp = ' ';            /* force exit from fast loop */
  257. f1:    if ( (val1 = decoder[sptr[1]]) <= 0xf &&
  258.          (val2 = decoder[sptr[2]]) <= 0xf
  259.        )
  260.        {    sptr += 2;
  261.         *ptr++ = (val1 << 4) + val2;
  262.         if ( ptr < limit ) goto f1;
  263.         *endp = save_last;
  264.         goto px;
  265.        }
  266.     *endp = save_last;
  267. x1:    while ( (val1 = decoder[ch = sgetc_inline(s, sptr, endp)]) > 0xf )
  268.        {    if ( val1 == ctype_eof )
  269.            {    code = ch; *odd_digit = -1; goto ended;    }
  270.         else if ( val1 != ctype_space && !ignore_garbage )
  271.            {    sptr--; *odd_digit = -1; goto err;    }
  272.        }
  273. d2:    while ( (val2 = decoder[ch = sgetc_inline(s, sptr, endp)]) > 0xf )
  274.        {    if ( val2 == ctype_eof )
  275.            {    code = ch; *odd_digit = val1; goto ended;    }
  276.         else if ( val2 != ctype_space && !ignore_garbage )
  277.            {    sptr--; *odd_digit = val1; goto err;    }
  278.        }
  279.     *ptr++ = (val1 << 4) + val2;
  280.     if ( ptr < limit ) goto d1;
  281. px:    *nread = rlen;
  282.     s_end_inline(s, sptr, endp);
  283.     return 0;
  284. err:    code = ERRC;
  285. ended:    *nread = ptr - str;
  286.     s_end_inline(s, sptr, endp);
  287.     return code;
  288. }
  289.  
  290. /* Skip a specified distance in a stream. */
  291. /* Return 0, EOFC, or ERRC. */
  292. int
  293. spskip(register stream *s, long n)
  294. {    if ( n < 0 || !s_is_reading(s) ) return ERRC;
  295.     if ( s_can_seek(s) )
  296.         return sseek(s, stell(s) + n);
  297.     while ( sbufavailable(s) < n )
  298.     {    int code;
  299.         n -= sbufavailable(s) + 1;
  300.         s->cptr = s->endptr;
  301.         if ( s->end_status )
  302.             return s->end_status;
  303.         code = sgetc(s);
  304.         if ( code < 0 ) return code;
  305.     }
  306.     s->cptr += n;
  307.     return 0;
  308. }    
  309.  
  310. /* ------ String streams ------ */
  311.  
  312. /* Initialize a stream for reading a string. */
  313. void
  314. sread_string(register stream *s, const byte *ptr, uint len)
  315. {    static const stream_procs p =
  316.        {    s_string_available, s_string_seek,
  317.         s_std_read_flush, s_std_null,
  318.         s_string_read_buf, NULL
  319.        };
  320.     s_string_init(s, (byte *)ptr, len, &p);
  321.     s->modes = s_mode_read + s_mode_seek;
  322. }
  323. /* Handle end-of-buffer when reading from a string. */
  324. private int
  325. s_string_read_buf(stream *s)
  326. {    s->cptr = s->endptr;
  327.     s->end_status = EOFC;
  328.     return EOFC;
  329. }
  330. /* Return the number of available bytes when reading from a string. */
  331. private int
  332. s_string_available(stream *s, long *pl)
  333. {    *pl = sbufavailable(s);
  334.     if ( *pl == 0 ) *pl = -1;    /* EOF */
  335.     return 0;
  336. }
  337.  
  338. /* Initialize a stream for writing a string. */
  339. void
  340. swrite_string(register stream *s, byte *ptr, uint len)
  341. {    static const stream_procs p =
  342.        {    s_std_noavailable, s_string_seek,
  343.         s_std_write_flush, s_std_null,
  344.         NULL, s_string_write_buf
  345.        };
  346.     s_string_init(s, ptr, len, &p);
  347.     s->modes = s_mode_write + s_mode_seek;
  348. }
  349. /* Handle end-of-buffer when writing a string. */
  350. private int
  351. s_string_write_buf(stream *s)
  352. {    s->cptr = s->endptr;
  353.     s->end_status = EOFC;
  354.     return EOFC;
  355. }
  356.  
  357. /* Seek in a string.  Return 0 if OK, ERRC if not. */
  358. private int
  359. s_string_seek(register stream *s, long pos)
  360. {    if ( pos < 0 || pos > s->bsize ) return ERRC;
  361.     s->cptr = s->cbuf + pos - 1;
  362.     return 0;
  363. }
  364.  
  365. /* Private initialization */
  366. private void
  367. s_string_init(register stream *s, byte *ptr, uint len, const stream_procs *pp)
  368. {    s_std_init(s, ptr, len, pp, s_mode_write);
  369.     s->end_status = EOFC;        /* this is all there is */
  370.     s->file = 0;            /* not a file stream */
  371. }
  372.  
  373. /* ------ File streams ------ */
  374.  
  375. /* Initialize a stream for reading an OS file. */
  376. void
  377. sread_file(register stream *s, FILE *file, byte *buf, uint len)
  378. {    static const stream_procs p =
  379.        {    s_file_available, s_file_read_seek,
  380.         s_std_read_flush, s_file_read_close,
  381.         s_file_read_buf, NULL
  382.        };
  383.     s_std_init(s, buf, len, &p,
  384.            (file == stdin ? s_mode_read : s_mode_read + s_mode_seek));
  385.     s->file = file;
  386. }
  387. /* Procedures for reading from a file */
  388. private int
  389. s_file_read_buf(register stream *s)
  390. {    int nread;
  391.     if ( s_can_seek(s) )
  392.         s->position = ftell(s->file);
  393.     nread = fread(s->cbuf, 1, s->bsize, s->file);
  394.     s->cptr = s->cbuf - 1;
  395.     s->end_status = (ferror(s->file) ? ERRC : feof(s->file) ? EOFC : 0);
  396.     if ( nread <= 0 ) nread = 0;
  397.     s->endptr = s->cptr + nread;
  398.     return 0;
  399. }
  400. private int
  401. s_file_available(register stream *s, long *pl)
  402. {    *pl = sbufavailable(s);
  403.     if ( sseekable(s) )
  404.        {    long pos, end;
  405.         pos = ftell(s->file);
  406.         if ( fseek(s->file, 0L, SEEK_END) ) return ERRC;
  407.         end = ftell(s->file);
  408.         if ( fseek(s->file, pos, SEEK_SET) ) return ERRC;
  409.         *pl += end - pos;
  410.         if ( *pl == 0 ) *pl = -1;    /* EOF */
  411.        }
  412.     else
  413.        {    if ( *pl == 0 && feof(s->file) ) *pl = -1;    /* EOF */
  414.        }
  415.     return 0;
  416. }
  417. private int
  418. s_file_read_seek(register stream *s, long pos)
  419. {    uint end = s->endptr - s->cbuf + 1;
  420.     long offset = pos - s->position;
  421.     if ( offset >= 0 && offset <= end )
  422.        {    /* Staying within the same buffer */
  423.         s->cptr = s->cbuf + offset - 1;
  424.         return 0;
  425.        }
  426.     if ( fseek(s->file, pos, SEEK_SET) != 0 )
  427.         return ERRC;
  428.     s->endptr = s->cptr = s->cbuf - 1;
  429.     s->end_status = 0;
  430.     return 0;
  431. }
  432. private int
  433. s_file_read_close(stream *s)
  434. {    return fclose(s->file);
  435. }
  436.  
  437. /* Initialize a stream for writing an OS file. */
  438. void
  439. swrite_file(register stream *s, FILE *file, byte *buf, uint len)
  440. {    static const stream_procs p =
  441.        {    s_std_noavailable, s_file_write_seek,
  442.         s_file_write_flush, s_file_write_close,
  443.         NULL, s_file_write_buf
  444.        };
  445.     s_std_init(s, buf, len, &p,
  446.            (file == stdout ? s_mode_write : s_mode_write + s_mode_seek));
  447.     s->file = file;
  448. }
  449. /* Initialize for appending to an OS file. */
  450. void
  451. sappend_file(register stream *s, FILE *file, byte *buf, uint len)
  452. {    swrite_file(s, file, buf, len);
  453.     s->modes = s_mode_write + s_mode_append;    /* no seek */
  454.     fseek(file, 0L, SEEK_END);
  455.     s->position = ftell(file);
  456. }
  457. /* Procedures for writing on a file */
  458. private int
  459. s_file_write_buf(register stream *s)
  460. {    uint count = s->cptr + 1 - s->cbuf;
  461.     uint write_count = fwrite(s->cbuf, 1, count, s->file);
  462.     if ( s_can_seek(s) )
  463.         s->position = ftell(s->file);
  464.     s->cptr = s->cbuf - 1;
  465.     if ( write_count != count )
  466.        {    s->end_status = (ferror(s->file) ? ERRC : EOFC);
  467.         s->endptr = s->cptr;
  468.        }
  469.     else
  470.         s->endptr = s->cptr + s->bsize;
  471.     gp_check_interrupts();
  472.     return 0;
  473. }
  474. private int
  475. s_file_write_seek(stream *s, long pos)
  476. {    /* We must flush the buffer to reposition. */
  477.     int code = sflush(s);
  478.     if ( code < 0 )
  479.         return code;
  480.     if ( fseek(s->file, pos, SEEK_SET) != 0 )
  481.         return ERRC;
  482.     s->position = pos;
  483.     return 0;
  484. }
  485. private int
  486. s_file_write_flush(register stream *s)
  487. {    int result = s_file_write_buf(s);
  488.     fflush(s->file);
  489.     return result;
  490. }
  491. private int
  492. s_file_write_close(register stream *s)
  493. {    s_file_write_buf(s);
  494.     return fclose(s->file);
  495. }
  496.